using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using System.IO.IsolatedStorage;
using System.IO;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using BattleCity.Rendering;
using BattleCity.GameLogic.Xml;


#if WINDOWS_PHONE
using Microsoft.Xna.Framework.Input.Touch;
#endif


namespace BattleCity
{
    public enum MenuStates
    {
        Logo,
        Main,
        Survival,
        SingleLevel,
        Scores,
        Options,
        None
    }
   
    public class MenuManager : Microsoft.Xna.Framework.DrawableGameComponent
    {
        //Menus
        SurvivalMenu    survivalMenu;
        MainMenu        mainMenu;
        OptionsMenu optionsMenu;
        SingleLevelMenu singleMenu;
        ScoresMenu scoresMenu;

        #if WINDOWS_PHONE
        IsolatedStorageFile IS = IsolatedStorageFile.GetUserStoreForApplication();
        #else
        IsolatedStorageFile IS = IsolatedStorageFile.GetUserStoreForDomain();
        bool mouseAlreadyPressed = false;
        bool escAlreadyPressed = false;
        #endif

        SpriteBatch spriteBatch;

        Texture2D logoSpace;
        Texture2D logoTank;
        Texture2D materialsTex;
        Texture2D background;

        int screenHeight;
        int screenWidth;

        Vector2 screenCenter;

        GridRenderer gridModel;
        BlocksRenderer blocksModel;
        BasicEffect effect;

        SpriteFont menuFont;

        bool tapStringVisible;
        float tapStringClock;
        Vector2 continueTapPosition;

        Texture2D menuWrapper;
        Texture2D buttonTexture;
        Texture2D tappedButtonTexture;

        Vector2 menuWrapperPosition;
        int wrapperWidth;

        MenuStates menuState;

        public Action survivalStart;
        public Action survivalContinue;
        public Action<int> singleLevelStart;
        public Action singleLevelContinue;

        bool survivalContinueAvailable;
        bool singleLevelContinueAvailable;

        public MenuManager(SpaceTankGame game, bool skipLogo)
            : base(game)
        {
            screenHeight = game.graphics.PreferredBackBufferHeight;
            screenWidth = game.graphics.PreferredBackBufferWidth;

            screenCenter = new Vector2(game.graphics.PreferredBackBufferWidth * 0.5f, game.graphics.PreferredBackBufferHeight * 0.5f);

            tapStringVisible = true;
            tapStringClock = 0.0f;

            if (skipLogo) menuState = MenuStates.Main;
            else menuState = MenuStates.Logo;

            if (IS.FileExists("survival.sav")) survivalContinueAvailable = true;
            else survivalContinueAvailable = false;

            if (IS.FileExists("level.sav")) singleLevelContinueAvailable = true;
            else singleLevelContinueAvailable = false;
           
            #if WINDOWS_PHONE
            TouchPanel.EnabledGestures = GestureType.Tap;
            #endif

            String path = @"Levels\menu.xml";
            Stream levelFileStream = TitleContainer.OpenStream(path);
            XmlSerializer deserializer = new XmlSerializer(typeof(SerializableTuple<BlockType, bool[]>[]));
            SerializableTuple<BlockType, bool[]>[] levelMap = (SerializableTuple<BlockType, bool[]>[])deserializer.Deserialize(levelFileStream);

            BattleCity.GameLogic.Xml.SerializableGameState.loadLevel(levelMap, false);
            levelFileStream.Close();
        }


        protected override void LoadContent()
        {
            effect = new BasicEffect(GraphicsDevice);

            menuFont = Game.Content.Load<SpriteFont>("menu");
            logoSpace = Game.Content.Load<Texture2D>(@"Menu\logospace");
            logoTank = Game.Content.Load<Texture2D>(@"Menu\logotank");
          
            materialsTex = Game.Content.Load<Texture2D>(@"block_textures\material_tex");
            buttonTexture = Game.Content.Load<Texture2D>(@"Menu\button");
            tappedButtonTexture = Game.Content.Load<Texture2D>(@"Menu\tapped_button");

            gridModel = new GridRenderer(GraphicsDevice);
            blocksModel = new BlocksRenderer(GraphicsDevice);
            
            #if WINDOWS_PHONE
            continueTapPosition = new Vector2(screenCenter.X - (menuFont.MeasureString(strings.CONTINUETAP).X) * 0.5f, 350.0f);
            wrapperWidth = 400;
            menuWrapper = new Texture2D(GraphicsDevice, wrapperWidth, screenHeight);
            menuWrapperPosition = new Vector2(screenCenter.X - 200, 0.0f);
            Color[] wrapperColorData = new Color[wrapperWidth * screenHeight];

            effect.View = Matrix.CreateLookAt(new Vector3(-1, 25, 0), new Vector3(-1, 0, 0), -Vector3.UnitZ);
            effect.Projection = Matrix.CreatePerspectiveFieldOfView(0.95f, GraphicsDevice.Viewport.AspectRatio, 1, 1000);
            #else
            continueTapPosition = new Vector2(screenCenter.X - (menuFont.MeasureString(strings.CONTINUECLICK).X) * 0.5f, 600.0f);
            wrapperWidth = 600;
            menuWrapper = new Texture2D(GraphicsDevice, wrapperWidth, screenHeight);
            menuWrapperPosition = new Vector2(screenCenter.X - 300, 0.0f);
            Color[] wrapperColorData = new Color[wrapperWidth * screenHeight];

            effect.View = Matrix.CreateLookAt(new Vector3(-1, 28, 0), new Vector3(-1, 0, 0), -Vector3.UnitZ);
            effect.Projection = Matrix.CreatePerspectiveFieldOfView(0.95f, GraphicsDevice.Viewport.AspectRatio, 1, 1000);
            #endif

            effect.DirectionalLight0.DiffuseColor = new Vector3(0.6f, 0.6f, 0.6f);
            effect.DirectionalLight0.Direction = new Vector3(0, -1, 0);
            effect.AmbientLightColor = new Vector3(0.1f, 0.1f, 0.1f);

            for (int i = 0; i < screenHeight; ++i)
            {
                for (int j = 0; j < wrapperWidth; ++j)
                {
                    if ((j == 0) || (j == wrapperWidth - 1)) 
                        wrapperColorData[(i * wrapperWidth) + j] = new Color(0, 250, 0, 200);
                    else                   
                        wrapperColorData[(i * wrapperWidth) + j] = new Color(0, 0, 0, 200);
                }
            }
            menuWrapper.SetData<Color>(wrapperColorData);

            Game.GraphicsDevice.Clear(Color.Black);
            RenderTarget2D renderTarget = new RenderTarget2D(GraphicsDevice, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8);
            GraphicsDevice.SetRenderTarget(renderTarget);
            DrawBackground();
            GraphicsDevice.SetRenderTarget(null);
            Color[] bgColorData = new Color[GraphicsDevice.Viewport.Width * GraphicsDevice.Viewport.Height];
            renderTarget.GetData<Color>(bgColorData);

            background = new Texture2D(GraphicsDevice, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
            background.SetData<Color>(bgColorData);
          
            base.LoadContent();
        }
        
        public override void Initialize()
        {
            base.Initialize();

            spriteBatch = new SpriteBatch(GraphicsDevice);
            survivalMenu = new SurvivalMenu(survivalContinueAvailable, screenCenter, menuFont, menuWrapper, buttonTexture, tappedButtonTexture, spriteBatch);
            singleMenu = new SingleLevelMenu(singleLevelContinueAvailable, screenCenter, menuFont, menuWrapper, spriteBatch, Game.Content, GraphicsDevice); 
            mainMenu = new MainMenu(screenCenter, menuFont, menuWrapper, buttonTexture, tappedButtonTexture, spriteBatch);
            optionsMenu = new OptionsMenu(screenCenter, menuFont, menuWrapper, buttonTexture, tappedButtonTexture, spriteBatch);
            scoresMenu = new ScoresMenu(screenCenter, menuFont, menuWrapper, spriteBatch, Game.Content);
        }

      
        public override void Update(GameTime gameTime)
        {
            #if WINDOWS_PHONE
            while (TouchPanel.IsGestureAvailable)
            {
                GestureSample gs = TouchPanel.ReadGesture();
                if (gs.GestureType == GestureType.Tap)
                {
                    switch (menuState)
                    {
                        case MenuStates.Logo:
                            menuState = MenuStates.Main;
                            break;

                        case MenuStates.Main:
                            mainMenu.Update(gs.Position);
                            break;

                        case MenuStates.Survival:
                            survivalMenu.Update(gs.Position);
                            break;

                        case MenuStates.SingleLevel:
                            singleMenu.Update(gs.Position);
                            break;

                        case MenuStates.Scores:
                            scoresMenu.Update(gs.Position, ref menuState);
                            break;

                        case MenuStates.Options:
                            optionsMenu.Update(gs.Position);
                            break;

                    }
                }  
            }
            #else
            MouseState mouseState = Mouse.GetState();
            if ((mouseState.LeftButton == ButtonState.Pressed) && !mouseAlreadyPressed)
            {
                mouseAlreadyPressed = true;
                Vector2 mousePosition = new Vector2(mouseState.X, mouseState.Y);
                switch (menuState)
                {
                    case MenuStates.Logo:
                        menuState = MenuStates.Main;
                        break;

                    case MenuStates.Main:
                        mainMenu.Update(mousePosition);
                        break;

                    case MenuStates.Survival:
                        survivalMenu.Update(mousePosition);
                        break;

                    case MenuStates.Options:
                        optionsMenu.Update(mousePosition);
                        break;

                    case MenuStates.SingleLevel:
                        singleMenu.Update(mousePosition);
                        break;

                }
            }
            else if (mouseState.LeftButton == ButtonState.Released) mouseAlreadyPressed = false;
            #endif

            mainMenu.UpdateCounter(ref menuState, (float)gameTime.ElapsedGameTime.TotalSeconds);
            optionsMenu.UpdateCounter((float)gameTime.ElapsedGameTime.TotalSeconds);
            singleMenu.UpdateCounter(this, (float)gameTime.ElapsedGameTime.TotalSeconds);
            survivalMenu.UpdateCounter(this, (float)gameTime.ElapsedGameTime.TotalSeconds);

            #if WINDOWS_PHONE
            if(GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            #else
            if (Keyboard.GetState().IsKeyUp(Keys.Escape)) escAlreadyPressed = false;
            if(Keyboard.GetState().IsKeyDown(Keys.Escape) && !escAlreadyPressed)
            #endif
            {
                #if !WINDOWS_PHONE
                escAlreadyPressed = true;
                #endif
                switch (menuState)
                {
                    case MenuStates.Main:
                        menuState = MenuStates.Logo;
                        break;

                    case MenuStates.Survival:
                        if (survivalMenu.warningMessage) survivalMenu.warningMessage = false;
                        else  menuState = MenuStates.Main;
                        break;

                    case MenuStates.Scores:
                        menuState = MenuStates.Main;
                        break;

                    case MenuStates.Options:
                        if (optionsMenu.optionsScreen == OptionsMenu.OptionsScreen.Main)
                            menuState = MenuStates.Main;
                        else optionsMenu.optionsScreen = OptionsMenu.OptionsScreen.Main;
                        break;

                    case MenuStates.SingleLevel:
                        if((singleMenu.levelChooser) && (singleMenu.continueAvailable)) singleMenu.levelChooser = !singleMenu.levelChooser;
                        else menuState = MenuStates.Main;
                        break;

                    case MenuStates.Logo:
                        Game.Exit();
                        break;
                }
            }

            //Gestisce il blinking della scritta nel menu del logo
            tapStringClock += (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (tapStringClock >= 0.5f)
            {
                tapStringVisible = !tapStringVisible;
                tapStringClock = 0;
            }

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            Game.GraphicsDevice.Clear(Color.Black);

            //DrawBackground();

            spriteBatch.Begin();

            if (singleMenu.newLevelView)
            {
                singleMenu.DrawLevel();
            }

            spriteBatch.Draw(background, Vector2.Zero, Color.White);

            switch(menuState)
            {
                case MenuStates.Logo:
                    spriteBatch.Draw(logoSpace, new Vector2(screenCenter.X - (logoSpace.Width * 0.5f), 30.0f), Color.White);
                    spriteBatch.Draw(logoTank, new Vector2(screenCenter.X - (logoTank.Width * 0.5f), 200.0f), Color.White);

                    if (tapStringVisible)
                    {
#if WINDOWS_PHONE
                        spriteBatch.DrawString(menuFont, strings.CONTINUETAP, continueTapPosition + new Vector2(2, 2), Color.Black);
                        spriteBatch.DrawString(menuFont, strings.CONTINUETAP, continueTapPosition, Color.DarkCyan);
#else
                        spriteBatch.DrawString(menuFont, strings.CONTINUECLICK, continueTapPosition, Color.Green);
#endif
                    }
                    break;
                case MenuStates.Main:
                    mainMenu.Draw();
                    break;
                case MenuStates.Survival:
                    survivalMenu.Draw();
                    break;
                case MenuStates.Scores:
                    scoresMenu.Draw();
                    break;
                case MenuStates.Options:
                    optionsMenu.Draw();
                    break;
                case MenuStates.SingleLevel:
                    singleMenu.Draw();
                    break;
            }
 

            spriteBatch.End();

            base.Draw(gameTime);
        }

        public void DrawBackground()
        {
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            //setto tecnica e materiali per il rendering della griglia e dei blocchi
            effect.World = Matrix.Identity;
            effect.LightingEnabled = true;
            effect.TextureEnabled = true;
            effect.Texture = materialsTex;
            effect.CurrentTechnique.Passes[0].Apply();

            //Grid Rendering
            GraphicsDevice.Indices = gridModel.IndexBuffer;
            GraphicsDevice.SetVertexBuffer(gridModel.VertexBuffer);
            GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, gridModel.VertexBuffer.VertexCount, 0, gridModel.PrimitiveCount);


            //Block Rendering
            GraphicsDevice.Indices = blocksModel.indexBuffers[0];
            GraphicsDevice.SetVertexBuffer(blocksModel.vertexBuffers[0]);
            GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, blocksModel.vertexBuffers[0].VertexCount, 0, blocksModel.PrimitiveCount(0));

            GraphicsDevice.Indices = blocksModel.indexBuffers[1];
            GraphicsDevice.SetVertexBuffer(blocksModel.vertexBuffers[1]);
            GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, blocksModel.vertexBuffers[1].VertexCount, 0, blocksModel.PrimitiveCount(1));
        }
    }
}
